package com.zige.zige.view.panoplayer.glwrapper;

import android.opengl.Matrix;
import android.util.Log;

/**
 * Created by admin on 16/1/5.
 */
public class GlCamera {
    private float fovy;

    private float aspect;

    private float near;

    private float far;

    private float[] position;

    private float[] up;

    private float[] dir;

    private float[] viewMatrix;

    private float[] perspectiveMatrix;

    private int updateMask;

    private final float[] INITIAL_VIEW_MATRIX;

    private static final int POSITION = 1 << 0;

    private static final int UP = 1 << 1;

    private static final int DIR = 1 << 2;

    public GlCamera() {
        fovy = 90.0f;
        aspect = 1.0f;
        near = 0.1f;
        far = 100.0f;
        viewMatrix = new float[16];
        perspectiveMatrix = new float[16];
        Matrix.setLookAtM(viewMatrix, 0,
                0.0f, 0.0f, 0.0f,
                0.0f, 0.0f, -1.0f,
                0.0f, 1.0f, 0.0f);
        Matrix.perspectiveM(perspectiveMatrix, 0, this.fovy, this.aspect, this.near, this.far);
        INITIAL_VIEW_MATRIX = viewMatrix.clone();
        position = new float[3];
        position[0] = position[1] = position[2] = 0.0f;
        up = new float[3];
        up[0] = up[2] = 0.0f;
        up[1] = 1.0f;
        dir = new float[3];
        dir[0] = dir[1] = 0.0f;
        dir[2] = -1.0f;

        updateMask = ~POSITION & ~UP & ~DIR;
    }

    public void rotateByAngle(float radian, float[] axis) {
        float[] rotation = new float[16];
        Matrix.setRotateM(rotation, 0, radian, axis[0], axis[1], axis[2]);
        this.rotate(rotation);
    }

    public void rotate(float[] rotation) {
        float[] tmp = viewMatrix.clone();
        Matrix.multiplyMM(this.viewMatrix, 0, tmp, 0, rotation, 0);
        updateMask |= (UP | DIR);
    }

    public void resetView() {
        viewMatrix = INITIAL_VIEW_MATRIX.clone();
        updateMask = POSITION | UP | DIR;
    }

    public float[] getDir() {
        if ((updateMask & DIR) != 0) {
            dir[0] = -viewMatrix[8];
            dir[1] = -viewMatrix[9];
            dir[2] = -viewMatrix[10];
            updateMask &= ~DIR;
        }
        return dir;
    }

    public float[] getPosition() {
        if ((updateMask & POSITION) != 0) {
            float[] mat3 = {
                    -viewMatrix[0], -viewMatrix[4], -viewMatrix[8],
                    -viewMatrix[1], -viewMatrix[5], -viewMatrix[9],
                    -viewMatrix[2], -viewMatrix[6], -viewMatrix[10]
            };
            float[] vec3 = {
                    viewMatrix[12], viewMatrix[13], viewMatrix[14]
            };
            Matrix.multiplyMV(this.position, 0, mat3, 0, vec3, 0);
            updateMask &= ~POSITION;
        }
        return position;
    }

    public float[] getUp() {
        if ((updateMask & UP) != 0) {
            up[0] = viewMatrix[4];
            up[1] = viewMatrix[5];
            up[2] = viewMatrix[6];
            updateMask &= ~UP;
        }
        return up;
    }

    public float getFovy() {
        return fovy;
    }

    public float getAspect() {
        return aspect;
    }

    public float getNear() {
        return near;
    }

    public float getFar() {
        return far;
    }

    public float[] getViewMatrix() {
        return viewMatrix;
    }

    public float[] getPerspectiveMatrix() {
        return perspectiveMatrix;
    }

    public void setFovy(float fovy) {
        this.fovy = fovy;
        Matrix.perspectiveM(this.perspectiveMatrix, 0, this.fovy, this.aspect, this.near, this.far);
    }

    public void setAspect(float aspect) {
        this.aspect = aspect;
        Log.w("camera", "aspect " + aspect);
        Matrix.perspectiveM(this.perspectiveMatrix, 0, this.fovy, this.aspect, this.near, this.far);
    }

    public void setNear(float near) {
        this.near = near;
        Matrix.perspectiveM(this.perspectiveMatrix, 0, this.fovy, this.aspect, this.near, this.far);
    }

    public void setFar(float far) {
        this.far = far;
        Matrix.perspectiveM(this.perspectiveMatrix, 0, this.fovy, this.aspect, this.near, this.far);
    }

    public void setViewMatrix(float[] viewMatrix) {
        this.viewMatrix = viewMatrix;
    }
}
